<template>
  <!-- 全屏滚动组件 -->
  <div
    class="full-page-wrapper"
    :style="{ position, height, width }"
    ref="fullPage"
  >
    <div
      class="all-page"
      ref="allPage"
      :style="{
        'transition-duration': transition.duration,
        'transition-timing-function': transition.timingFun,
        'transition-delay': transition.delay,
      }"
    >
      <template v-for="(item, index) in pagesArr">
        <div
          class="page"
          :class="{ floatLeft: !isV }"
          :key="index"
          :style="{
            height: fullHeight + 'px',
            width: fullWidth + 'px',
            'background-color':
              bgArr.length > 0 && bgArr[index] && !bgArr[index].isBg
                ? bgArr[index]
                : '',
            'background-image':
              bgArr.length > 0 && bgArr[index] && bgArr[index].isBg
                ? `url(${bgArr[index].src})`
                : '',
          }"
          :ref="`page${item}`"
        >
          <template v-if="isCache">
            <div class="page-box" v-show="item.isShow">
              <slot :name="`page${item.page}`" :data="item"></slot>
            </div>
          </template>
          <template v-else>
            <div class="page-box" v-show="page == item.page">
              <slot :name="`page${item.page}`" :data="item"></slot>
            </div>
          </template>
        </div>
      </template>
    </div>
    <div class="pointer-wrapper" :class="pointerPos" v-if="isPointer">
      <ul :class="isPc && 'hover'">
        <li
          :class="{ active: page == index }"
          @click.stop="pointerClick(index)"
          v-for="index in pages"
          :key="index"
        ></li>
      </ul>
    </div>
  </div>
</template>

<script>
/**
 * @description vue全屏滚动组件(支持PC端和移动端)
 * @author maybe
 * @warn 转载请注明出处 https://gitee.com/null_639_5368/v-full-page
 */
// 禁止IOS回弹库
import inobounce from "./inobounce";
import {
  debounce,
  throttle,
  isFireFox,
  addEvent,
  removeEvent,
  eventPath,
} from "./utils";
export default {
  name: "MvFullPage",
  props: {
    // 自定义过渡动画
    transition: {
      type: Object,
      default: function () {
        return {
          duration: "1000ms", // 动画时长
          timingFun: "ease", // 动画速度曲线
          delay: "0s", // 动画延迟
        };
      },
    },
    /**
     * 是否显示指示器
     */
    isPointer: {
      type: Boolean,
      default: true,
    },
    /**
     * 指示器位置
     */
    pointerPos: {
      type: String,
      default: "right",
    },
    /**
     * 定位模式
     */
    position: {
      type: String,
      default: "fixed",
    },
    /**
     * 自定义容器宽度
     */
    width: {
      type: String,
      default: "100%",
    },
    /**
     * 自定义容器高度
     */
    height: {
      type: String,
      default: "100%",
    },
    /**
     * 滚动的方向 true为垂直方向，false为左右方向
     */
    isV: {
      type: Boolean,
      default: true,
    },
    /**
     * 是否缓存页面
     */
    isCache: {
      type: Boolean,
      default: true,
    },
    /**
     * 页面总数
     */
    pages: {
      type: [Number, String],
      default: 4,
    },
    /**
     * 当前页面
     */
    page: {
      type: [Number, String],
      default: 1,
    },
    /**
     * 默认页面背景
     */
    bgArr: {
      type: Array,
      default: function () {
        return [];
      },
    },
  },
  data() {
    return {
      pagesArr: [],
      isPc: false, // 默认 移动端
      fullHeight: 800, // 全屏高度
      fullWidth: 1920, // 全屏宽度
      maxY: 0,
      maxX: 0,
      startY: 0,
      endY: 0,
      startX: 0,
      endX: 0,
      currentPage: 1, // 当前页面页码
      isRock: false, // 是否锁定页面避免多次触发出现bug
      isUp: false, // 是否向上滑动
      subScrollEl: null, // 触发源为内部滚动子元素dom
      wheelEventName: null, // 不同浏览器环境下滚轮事件名称
      isInitTranslate: false, // 是否初始化位置
    };
  },
  computed: {},
  created() {
    this.isPc = this.isPCFn();
    if (!this.isPc) {
      console.log("当前mv-full-page运行环境为: 移动端");
      // let isIos = this.isIOS();
      // if (isIos) {
      //   inobounce.enable()
      // }
      // 由于安卓微信公众号也存在类似问题，现全平台开启滚动禁用
      inobounce.enable();
    } else {
      console.log("当前mv-full-page运行环境为: PC端");
    }
  },
  mounted() {
    this.$nextTick(() => {
      // 初始化页面宽高
      this.initPageWH();
      // 初始化页面滑动事件
      this.initPageListener();
    });
    // 响应窗口大小
    window.addEventListener("resize", this.resizeFn);
  },
  watch: {
    page: {
      handler: function (val) {
        // 是否需要重置位置（避免页面显示错误的过渡动画）
        if (this.isInitTranslate) {
          this.startRoll(0);
          this.isInitTranslate = false;
          // 用setTimeout进入异步队列避免还没重置位置就提前解除过渡动画锁定
          setTimeout(() => {
            this.$refs.allPage.classList.remove("transition-clear");
          }, 1);
          return;
        }
        this.$nextTick(() => {
          // 设置当前页面为可视页面
          this.pagesArr[this.page - 1].isShow = true;
          // 动画切换页面
          this.rollPage(val);
        });
      },
      immediate: false,
    },
    pages: {
      handler: function (val) {
        if (!this.pages || this.pages <= 0) {
          return;
        }
        this.pagesArr.length = 0;
        for (let index = 0; index < this.pages; index++) {
          this.pagesArr.push({
            page: index + 1,
            isShow: index == 0 ? true : false,
          });
        }
        // 初始化设置页面1为可视页面
        this.pagesArr[0].isShow = true;
        // 如果当前页码大于1重置位置（避免页面显示错误的过渡动画）
        if (this.page > 1) {
          // 页面数改变标识
          this.$refs.allPage &&
            this.$refs.allPage.classList.add("transition-clear");
          this.isInitTranslate = true;
        }

        // 初始化切换页面
        this.$emit("update:page", 1);
      },
      immediate: true,
    },
  },
  methods: {
    // 监听页面动画结束
    addPageTransEndListener(fn) {
      const eventFn = () => {
        // this.$emit("rollEnd", self.page);
        fn();
        this.$refs.allPage.removeEventListener("transitionend", eventFn);
      };
      this.$refs.allPage.addEventListener("transitionend", eventFn);
    },
    // 根据偏移量开始滚动
    startRoll(offset) {
      let transformBind = `translate${this.isV ? "Y" : "X"}(${offset}px)`;
      this.$refs.allPage.style.transform = transformBind;
    },
    // 响应窗口大小监听函数
    resizeFn: throttle(function () {
      console.log(this.$refs);
      // 初始化页面宽高
      this.initPageWH();
    }, 500),
    // 指示器点击
    pointerClick(index) {
      if (this.isRock) return;
      this.$emit("update:page", index);
    },
    /**
     * 判断是否是ios系统
     */
    isIOS() {
      let u = navigator.userAgent;
      if (u.indexOf("iPhone") > -1) {
        return true;
      }
      return false;
    },
    /**
     * 判断是否是PC端
     */
    isPCFn() {
      var userAgentInfo = navigator.userAgent;
      var Agents = [
        "Android",
        "iPhone",
        "SymbianOS",
        "Windows Phone",
        "iPad",
        "iPod",
      ];
      var flag = true;
      for (var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
          flag = false;
          break;
        }
      }
      return flag;
    },
    // 初始化容器宽高
    initPageWH() {
      // 获取全屏高度
      this.fullHeight = this.$refs.fullPage.clientHeight;
      // 获取全屏宽度
      this.fullWidth = this.$refs.fullPage.clientWidth;
      // 设置最大滑动高度
      this.maxY = this.pages * this.fullHeight;
      // 设置最大滑动宽度
      this.maxX = this.pages * this.fullWidth;
      // 初始化容器高度
      this.$refs.allPage.style.height = this.fullHeight * this.pages + "px";
      // 初始化容器宽度
      this.$refs.allPage.style.width = this.fullWidth * this.pages + "px";
    },
    initPageListener() {
      if (!this.isPc) {
        this.$refs.allPage.addEventListener(
          "touchstart",
          this.pageStart,
          false
        );
        this.$refs.allPage.addEventListener("touchmove", this.pageMove, false);
        this.$refs.allPage.addEventListener("touchend", this.pageEnd, false);
      } else {
        // pc端鼠标滚轮事件监听 使用函数防抖解决滚动多次触发问题
        // 判断不同浏览器环境下滚轮事件名称
        this.wheelEventName = isFireFox() ? "DOMMouseScroll" : "mousewheel";
        addEvent(this.$refs.allPage, this.wheelEventName, this.pcRoll);
      }
    },
    removePageListener() {
      if (!this.isPc) {
        // 解除滚动禁用
        inobounce.disable();
        this.$refs.allPage.removeEventListener("touchstart", this.pageStart);
        this.$refs.allPage.removeEventListener("touchmove", this.pageMove);
        this.$refs.allPage.removeEventListener("touchend", this.pageEnd);
      } else {
        removeEvent(this.$refs.allPage, this.wheelEventName, this.pcRoll);
      }
    },
    // pcRoll: debounce(
    //   function (e) {
    //     // debugger;
    //     if (this.isRock) return;
    //     //#region 解决鼠标滚轮冲突
    //     // 获取事件冒泡路径
    //     let path = eventPath(e);
    //     let isSubScroll = Array.from(path).some((el) => {
    //       if (el.dataset && el.dataset.scroll == "true") {
    //         return true;
    //       }
    //       return false;
    //     });
    //     // 如果是子元素滚动直接终止父元素滚动
    //     if (isSubScroll) return;
    //     //#endregion
    //     // 判断是否达到滚动条件
    //     if (e.deltaY > 0 || e.detail > 0 || e.wheelDelta < 0) {
    //       // console.log("滚动下");
    //       this.switchPage(true);
    //     } else {
    //       this.switchPage(false);
    //       // console.log("滚动上");
    //     }
    //   },
    //   100,
    //   true
    // ),
    pcRoll(e) {
      // debugger;
      if (this.isRock) return;
      //#region 解决鼠标滚轮冲突
      // 获取事件冒泡路径
      let path = eventPath(e);
      let isSubScroll = Array.from(path).some((el) => {
        if (el.dataset && el.dataset.scroll == "true") {
          return true;
        }
        return false;
      });
      // 如果是子元素滚动直接终止父元素滚动
      if (isSubScroll) return;
      //#endregion
      // 判断是否达到滚动条件
      if (e.deltaY > 0 || e.detail > 0 || e.wheelDelta < 0) {
        // console.log("滚动下");
        this.switchPage(true);
      } else {
        this.switchPage(false);
        // console.log("滚动上");
      }
    },
    pageStart(e) {
      let self = this;
      console.log(e);
      let path = eventPath(e);
      // 判断是否是子元素滚动
      path.forEach((el) => {
        if (el.dataset && el.dataset.scroll == "true") {
          // 保存子元素实例
          self.subScrollEl = el;
        }
        // console.log(el)
      });
      if (self.subScrollEl) {
        // console.log('处理子元素滚动');
        inobounce.disable();
      } else {
        // console.log('处理插件滚动');
        inobounce.enable();
      }
      // console.log('触摸开始')
      this.startY = e.changedTouches[0].pageY;
      this.startX = e.changedTouches[0].pageX;
      // console.log(e.changedTouches[0].pageY, e.changedTouches[0].pageX)
    },
    pageMove(e) {
      let self = this;
      // console.log('触摸移动中...')
      if (
        self.subScrollEl &&
        self.subScrollEl.scrollTop == 0 &&
        e.changedTouches[0].pageY - this.startY > 0
      ) {
        // 子元素顶部向下滑动禁用回弹
        inobounce.enable();
      }
    },
    pageEnd(e) {
      // console.log('触摸结束')
      if (this.isRock) return;
      // // 判断是否是子元素滚动
      if (this.subScrollEl) {
        this.subScrollEl = null;
        inobounce.enable();
        // console.log('子元素滚动结束')
        return;
      }
      // 滑动逻辑
      if (this.isV) {
        if (e.changedTouches[0].pageY - this.startY < -50) {
          this.startY = null;
          this.switchPage(true);
        } else if (e.changedTouches[0].pageY - this.startY > 50) {
          this.startY = null;
          this.switchPage(false);
        }
      } else {
        if (e.changedTouches[0].pageX - this.startX < -50) {
          this.startX = null;
          this.switchPage(true);
        } else if (e.changedTouches[0].pageX - this.startX > 50) {
          this.startX = null;
          this.switchPage(false);
        }
      }
    },
    rollPage(page) {
      // debugger;
      const self = this;
      if (this.$refs.allPage) {
        let offset = -(
          (page - 1) *
          (this.isV ? this.fullHeight : this.fullWidth)
        );
        let transformBind = `translate${this.isV ? "Y" : "X"}(${offset}px)`;
        this.$refs.allPage.style.transform = transformBind;
        this.isRock = true;
        const eventFn = () => {
          this.isRock = false; // 解除锁定
          this.$emit("rollEnd", self.page);
          this.$refs.allPage.removeEventListener("transitionend", eventFn);
        };
        this.$refs.allPage.addEventListener("transitionend", eventFn);
      }
    },
    /**
     * 切换页面
     * @param   {Boolean} forward 滑动方向 前进方向 true  后退方向 false
     * @author   maybe
     */
    switchPage(forward = true) {
      // debugger;
      if (this.$refs.allPage) {
        // let rollY;
        // let rollX;
        let rollOffset;
        if (forward && this.page < this.pages) {
          // this.isRoll = true;
          // // 设置下一页为可视
          // this.pagesArr[this.page + 1 - 1].isShow = true;
          // rollOffset = -(
          //   this.page * (this.isV ? this.fullHeight : this.fullWidth)
          // );
          // // 页面开始滑动
          // let transformBind = `translate${
          //   this.isV ? "Y" : "X"
          // }(${rollOffset}px)`;
          // this.$refs.allPage.style.transform = transformBind;
          // let self = this;
          // let rollTransitionend = () => {
          //   setTimeout(() => {}, 100);
          //   // console.log("解除滑动限制");
          //   self.isRoll = false;
          //   self.$emit("update:page", this.page + 1);
          //   this.$refs.allPage.removeEventListener(
          //     "transitionend",
          //     rollTransitionend
          //   );
          // };
          // this.$refs.allPage.addEventListener(
          //   "transitionend",
          //   rollTransitionend
          // );

          this.$emit("update:page", this.page + 1);
        } else if (!forward && this.page > 1) {
          // this.isRoll = true;
          // // 设置上一页为可视
          // this.pagesArr[this.page - 1 - 1].isShow = true;
          // rollOffset =
          //   -((this.page - 1) * (this.isV ? this.fullHeight : this.fullWidth)) +
          //   (this.isV ? this.fullHeight : this.fullWidth);
          // // 页面开始滑动
          // let transformBind = `translate${
          //   this.isV ? "Y" : "X"
          // }(${rollOffset}px)`;
          // this.$refs.allPage.style.transform = transformBind;
          // let self = this;
          // let rollTransitionend = () => {
          //   setTimeout(() => {
          //     // console.log("解除滑动限制");
          //   }, 100);
          //   self.isRoll = false;
          //   self.$emit("update:page", this.page - 1);
          //   this.$refs.allPage.removeEventListener(
          //     "transitionend",
          //     rollTransitionend
          //   );
          // };
          // this.$refs.allPage.addEventListener(
          //   "transitionend",
          //   rollTransitionend
          // );

          this.$emit("update:page", this.page - 1);
        }
      }
    },
  },
  beforeDestroy() {
    // 销毁页面事件
    this.removePageListener();
    window.removeEventListener("resize", this.resizeFn);
    console.log("销毁页面事件成功");
  },
};
</script>

<style scoped lang="scss">
// .fixed {
//   position: fixed !important;
// }
// .relative {
//   position: relative !important;
// }
.full-page-wrapper {
  position: fixed;
  top: 0px;
  left: 0px;
  // width: 100%;
  // height: 100%;
  background: #ffffff;
  overflow: hidden;
  .all-page {
    width: 100%;
    transform: translateY(0px);
    -webkit-overflow-scrolling: touch;
    // transition: all 700ms ease 0s;
    transition-property: transform;
    transition-duration: 700ms;
    transition-timing-function: ease;
    transition-delay: 0s;
  }
  .page {
    z-index: 11;
    background-size: cover;
    background-repeat: no-repeat;
    position: relative;
    background-size: cover;
  }
  .page-box {
    position: absolute;
    height: 100%;
    width: 100%;
  }
}
.floatLeft {
  float: left;
}
.pointer-wrapper {
  position: fixed;
  &.right {
    right: 15px;
    top: 50%;
    transform: translateY(-50%);
    li {
      display: block;
      margin: 10px 0px;
    }
  }
  &.left {
    left: 15px;
    top: 50%;
    transform: translateY(-50%);
    li {
      display: block;
      margin: 10px 0px;
    }
  }
  &.top {
    top: 15px;
    left: 50%;
    transform: translateX(-50%);
    li {
      display: inline-block;
      margin: 0px 10px;
    }
  }

  &.bottom {
    bottom: 15px;
    left: 50%;
    transform: translateX(-50%);
    li {
      display: inline-block;
      margin: 0px 10px;
    }
  }

  ul > li {
    box-sizing: border-box;
    list-style: none;
    width: 15px;
    height: 15px;
    border: 2px solid transparent;
    border-radius: 50%;
    background-color: #fff;
    vertical-align: middle;
    cursor: pointer;
    transition: all 0.2s;
    &.active {
      border: 2px solid #fff;
      background-color: #00a1d6;
      transform: scale(1.3);
    }
  }
}
.hover li:hover {
  border: 2px solid #fff;
  background-color: #00a1d6;
  transform: scale(1.3);
}
.transition-clear {
  transition: none !important;
}
</style>
